package lesbonsamis;

import java.util.ArrayList;
import java.util.List;

class Algo {

    List<AB> listAB;	// liste des meilleures solutions
    AB meilleurAB;
    AB ab;

    int somBmin;
    int somBmax;
    int nbTransMin;

    public Algo(Projet projet) {
        this.somBmin = Integer.MAX_VALUE;
        this.nbTransMin = Integer.MAX_VALUE;
        this.listAB = new ArrayList<AB>();
		
        int[] depart = new int[projet.getParticipants().size()];
		int i = 0;
		
		for (Participant participant : projet.getParticipants()) {
			depart[i] = participant.getDifferentielVal().intValue();
			i++;
		}
		
        this.ab = new AB(depart);
    }
    
    public boolean init() {
        int taille = ab.A.length;
        int somme = 0;
        int pos = 0;
        int neg = 0;
        
    	for (int i = 0; i < taille; i++) {
    		somme += ab.A[i];
    	}
    	
    	for (int i = 0; i < taille; i++) {
    		if(ab.A[i] < 0) {
    			pos += ab.A[i];
    			somme += ab.A[i];
    		}
    		if(ab.A[i] > 0) {
    			neg += ab.A[i];
    			somme += ab.A[i];
    		}
    	}
		somBmax = Math.max(neg, pos);
    	
    	return somme == 0;
    }
    
    public void calcul() {
    	donne(this.ab);
    }
    
    private void donne(AB ab) {
        int taille = ab.A.length;
        AB abprim = new AB(ab);
        
        for (int i = 0; i < taille; i++) {
            for (int j = 0; j < taille; j++) {
            	if ((i != j) && (((abprim.minA(i)) && (abprim.maxA(j))) || ((abprim.maxA(i)) && (abprim.minA(j))))) {
                    AB absec = new AB(abprim);
                    absec.transaction(i,j);
                    absec.reduire();
                    //absec.afficher();
                    
                    int somB = absec.somB();
                    int nbTrans = absec.nbTrans();
                    if ((nbTrans <= nbTransMin) && (somB <= somBmin) && !listAB.contains(absec)) {
                        if (!absec.nulA()) {
                            donne(absec);
                        } else {
                            somBmin = somB;
                            nbTransMin = nbTrans;
                            eval(absec, somB, nbTrans);
                        }
                    }
                }
            }
        }
    }
    

    private void eval(AB ab, int somBEval, int nbTransEval) {
    	int somB = Integer.MAX_VALUE;
        int nbTrans = Integer.MAX_VALUE;
        
    	if (!listAB.isEmpty()) {
            somB = listAB.get(0).somB();
            nbTrans = listAB.get(0).nbTrans();
        }
        if ((somBEval < somB) || (nbTransEval < nbTrans)) {
            listAB.clear();
            //System.out.println("Une meilleure solution, somBEval=" + somBEval + " nbTransEval=" + nbTransEval);
            //ab.afficher();
        }
        
        listAB.add(ab);
    }

    public void afficher() {
        System.out.println("Solutions : " + listAB.size());
        for(AB ab : listAB) {
            ab.afficher();
        }
    }
    
    public List<TransactionCommand> transaction(Projet projet) {
    	List<TransactionCommand> transactions = new ArrayList<TransactionCommand>();
    	
    	if (!listAB.isEmpty()) {
	    	AB ab = listAB.get(0);
	    	int taille = ab.A.length;
	        
	    	for (int i = 0; i < taille; i++) {
	        	for (int j = 0; j < taille; j++) {
	        		if (ab.B[i][j] != 0) {
	        			TransactionCommand t = new TransactionCommand();
						t.setDonneur(projet.getParticipants().get(j));
						t.setReceveur(projet.getParticipants().get(i));
						t.setMontantVal(ab.B[i][j]);
	        			transactions.add(t);
	        		}
	        	}
	    	}
    	}
    	
    	return transactions;
    }
}